﻿using System;
using System.Linq;
using System.Windows.Forms;

using Spencen.Mobile.UI.Commanding;
using Spencen.Mobile.UI.Primitives;

namespace Spencen.Mobile.UI.Controls
{
    public class View : DrawingContainer
    {
        private MenuBar _menuBar;

        public View( IDrawingHost host ) : base ( host )
        {
        }

        public MenuBar MenuBar
        {
            get { return _menuBar; }
            set
            {
                if ( _menuBar != value )
                {
                    _menuBar = value;
                    Host.Menu = _menuBar;
                }
            }
        }

        protected override void OnRender( GraphicsContext context )
        {
            // The first time the view is rendered we set the intial focus.
            if ( _focusedElement == null )
            {
                _focusedElement = GetNextFocusElement( this );
                if ( _focusedElement != null )
                    _focusedElement.HasFocus = true;
            }

            base.OnRender( context );
        }

        #region Focus Stuff

        private DrawingElement _focusedElement;

        internal void ProcessKeyDown( System.Windows.Forms.KeyEventArgs e )
        {
            switch ( e.KeyData )
            {
                case Keys.Up:
                    if ( _focusedElement != null )
                    {
                        _focusedElement.HasFocus = false;
                        _focusedElement.Invalidate();
                    }
                    _focusedElement = GetPreviousFocusElement( _focusedElement ?? this );
                    if ( _focusedElement != null )
                    {
                        _focusedElement.HasFocus = true;
                        _focusedElement.Invalidate();
                    }
                    break;
                case Keys.Down:
                    if ( _focusedElement != null )
                    {
                        _focusedElement.HasFocus = false;
                        _focusedElement.Invalidate();
                    }
                    _focusedElement = GetNextFocusElement( _focusedElement ?? this );
                    if ( _focusedElement != null )
                    {
                        _focusedElement.HasFocus = true;
                        _focusedElement.Invalidate();
                    }
                    break;
                case Keys.Left:
                    break;
                case Keys.Right:
                    break;
                case Keys.Enter:
                    var commandSource = _focusedElement as ICommandSource;
                    if ( commandSource != null && commandSource.Command != null )
                        commandSource.Command.Execute();
                    break;
                case Keys.F8:
                    break;
                case Keys.F9:
                    break;
            }
        }

        private DrawingElement GetNextFocusElement( DrawingElement currentFocus )
        {
            // First go through the children
            var childFocusElement =  GetChildFocusElement( currentFocus, true );
            if ( childFocusElement != null )
                return childFocusElement;

            // Then to siblings
            var siblingFocusElement = GetNextSiblingFocusElement( currentFocus );
            if ( siblingFocusElement != null )
                return siblingFocusElement;

            // Then to parents siblings
            if ( currentFocus.Parent != null )
            {
                siblingFocusElement = GetNextSiblingFocusElement( currentFocus.Parent );
                if ( siblingFocusElement != null )
                    return siblingFocusElement;

                // TODO: Wrap to start but prevent recursive loop
            }

            return null;
        }

        private DrawingElement GetChildFocusElement( DrawingElement currentFocus, bool ascendingOrder )
        {
            var drawingContainer = currentFocus as DrawingContainer;
            if ( drawingContainer != null )
            {
                var list = ascendingOrder ? drawingContainer.Children.AsEnumerable() : drawingContainer.Children.Reverse();
                foreach ( var childElement in list )
                {
                    if ( childElement.CanFocus )
                        return childElement;

                    var childFocused = GetChildFocusElement( childElement, ascendingOrder );
                    if ( childFocused != null )
                        return childFocused;
                }
            }
            return null;
        }

        private DrawingElement GetNextSiblingFocusElement( DrawingElement currentFocus )
        {
            if ( currentFocus.Parent != null )
            {
                var parent = currentFocus.Parent as DrawingContainer;
                if ( parent != null )
                {
                    var currentIndex = parent.Children.IndexOf( currentFocus );
                    for ( int index = currentIndex + 1; index < parent.Children.Count; index++ )
                    {
                        var siblingElement = parent.Children[ index ];
                        if ( siblingElement.CanFocus )
                            return siblingElement;
                        else
                        {
                            var siblingFocused = GetChildFocusElement( siblingElement, true );
                            if ( siblingFocused != null )
                                return siblingFocused;
                        }
                    }
                }
            }
            return null;
        }

        private DrawingElement GetPreviousFocusElement( DrawingElement currentFocus )
        {
            // First to siblings
            var siblingFocused = GetPreviousSiblingFocusElement( currentFocus );
            if ( siblingFocused != null )
                return siblingFocused;

            // Then to parents siblings
            if ( currentFocus.Parent != null )
                return GetPreviousSiblingFocusElement( currentFocus.Parent );

            return null;
        }

        private DrawingElement GetPreviousSiblingFocusElement( DrawingElement currentFocus )
        {
            if ( currentFocus.Parent != null )
            {
                var parent = currentFocus.Parent as DrawingContainer;
                if ( parent != null )
                {
                    var currentIndex = parent.Children.IndexOf( currentFocus );
                    for ( int index = currentIndex - 1; index >= 0; index-- )
                    {
                        var siblingElement = parent.Children[ index ];
                        if ( siblingElement.CanFocus )
                            return siblingElement;
                        else
                        {
                            var siblingFocused = GetChildFocusElement( siblingElement, false );
                            if ( siblingFocused != null )
                                return siblingFocused;
                        }
                    }
                }
            }
            return null;
        }

        #endregion
    }
}
